home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / nasanets.zip / BUILDNET.C < prev    next >
C/C++ Source or Header  |  1990-06-07  |  38KB  |  871 lines

  1. /*=============================*/
  2. /*           NETS              */
  3. /*                             */
  4. /* a product of the AI Section */
  5. /* NASA, Johnson Space Center  */
  6. /*                             */
  7. /* principal author:           */
  8. /*       Paul Baffes           */
  9. /*                             */
  10. /* contributing authors:       */
  11. /*      Bryan Dulock           */
  12. /*      Chris Ortiz            */
  13. /*=============================*/
  14.  
  15.  
  16. /*
  17. ----------------------------------------------------------------------
  18.   Code For Construction Of Net Structures (Prefix = B_)
  19. ----------------------------------------------------------------------
  20.   This code is divided into 4 major sections:
  21.  
  22.   (1) include files
  23.   (2) externed functions
  24.   (3) externed global variables
  25.   (4) subroutines
  26.  
  27.   Each section is further explained below.
  28. ----------------------------------------------------------------------
  29. */
  30.  
  31.  
  32. /*
  33. ----------------------------------------------------------------------
  34.   INCLUDE FILES
  35. ----------------------------------------------------------------------
  36. */
  37. #include "common.h"
  38. #include "weights.h"
  39. #include "layer.h"
  40. #include "net.h"
  41. #include "netio.h"
  42.  
  43.  
  44. /*
  45. ----------------------------------------------------------------------
  46.   EXTERNED FUNCTIONS
  47. ----------------------------------------------------------------------
  48.   Below are the functions defined in other files which are used by the
  49.   code here. They are organized by section.
  50. ----------------------------------------------------------------------
  51. */
  52. extern  float        LR_learn_default();
  53. extern  float        LR_momentum_default();
  54. extern  float        LR_scale_default();
  55. extern  float        LR_learn_from_scale();
  56.  
  57. extern  Layer        *L_alloc_layer();
  58. extern  Layer_lst    *L_alloc_layer_lst();
  59. extern  Layer_lst    *L_insert_before();
  60. extern  void         L_free_layer();
  61. extern  void         L_free_layer_lst();
  62.  
  63. extern  Weights      *W_alloc_weights();
  64. extern  Weights_lst  *W_alloc_weights_lst();
  65. extern  Weights_lst  *W_insert_before();
  66. extern  void         W_weight_range();
  67.  
  68. extern  void         IO_my_get_string();
  69. extern  float        IO_get_default_float();
  70. extern  void         IO_print();
  71. extern  void         IO_insert_format();
  72.  
  73. extern  Layer_spec   *PS_get_layer();
  74. extern  void         PS_reset_for_layer_parse();
  75. extern  int          PS_global_spec_check();
  76.  
  77. extern  Sint         C_float_to_Sint();
  78. extern  char         *sys_alloc();
  79. extern  void         sys_free();
  80.  
  81.  
  82. /*
  83. ----------------------------------------------------------------------
  84.   EXTERNED GLOBALS
  85. ----------------------------------------------------------------------
  86.   Note that one global here is externed ONLY if we are in delivery mode.
  87.   If so, this global is used to indicate whether or not the delivery
  88.   network uses bias values. That is, the delivery code will define the
  89.   "bias_flag" global properly to indicate the presence of biases.
  90. ----------------------------------------------------------------------
  91. */
  92. extern float  global_learn_base;
  93. extern float  global_momentum;
  94. extern char   IO_str[MAX_LINE_SIZE];
  95. extern char   IO_wkstr[MAX_LINE_SIZE];
  96.  
  97.  
  98. /*
  99. ======================================================================
  100.   ROUTINES IN BUILDNET.C                                                   
  101. ======================================================================
  102.   The routines in this file are grouped below by function.  Each routine
  103.   is prefixed by the string "B_" indicating that it is defined in the 
  104.   "buildnet.c" file.  The types returned by the routines are also shown 
  105.   here so that cross checking is more easily done between these functions
  106.   and the other files which intern them.
  107.  
  108.  
  109.   Type Returned                 Routine                                 
  110.   -------------                 -------                                 
  111.     Net *                       B_create_net                            
  112.     int                         B_process_config                        
  113.     int                         B_create_wts                         
  114.     int                         B_check_layer_sizes   
  115.     void                        B_setup_net                             
  116.     void                        B_setup_learning  
  117.     void                        B_set_layer_learning  
  118.     void                        B_set_layer_momentum  
  119.     Net *                       B_free_net                          
  120. ======================================================================
  121. */
  122.  
  123.  
  124. Net  *B_create_net(id_num, file_name)
  125. int    id_num;                   /* identificaion # of net         */
  126. char   file_name[];              /* file with configuration of net */
  127. /*
  128. ----------------------------------------------------------------------
  129.  The routine generates a net in the following way. As each Layer_spec 
  130.   is processed, a Layer is created but WITHOUT any connections to     
  131.   weight arrays.  The trick is that the weight arrays cannot be made  
  132.   until all of the Layers are made! Thus as the layers are processed, 
  133.   an intermediate array of weight connections between layers is also  
  134.   generated.  Then, when all the layers have been processed, this     
  135.   array of weight connections is traversed and the Weights are created.
  136.  The array of weight connections (called 'wts_matrix') is a 2-d array 
  137.   whose first dimension represents SOURCE layers, and whose second    
  138.   dimension represents TARGET layers.  If a SOURCE-to-TARGET weight   
  139.   connection exists, then the corresponding entry in the array will    
  140.   have the value 1; otherwize, the value is zero.                     
  141.  The work of this routine is split up among subroutines: first, one  
  142.   named 'B_process_config' which creates the intermediate wts_matrix; 
  143.   then 'B_create_wts' which allocates space for the weights and sets up 
  144.   the pointers between the layers and weights; and finally 'B_setup_net'
  145.   which sets up the values in the final net structure.                
  146.  Notice how 'result->ID' is initially set to -1.  This translates to  
  147.   a bad net and is this routine's signal for returning an error.     
  148.   Thus if 'B_process_config' hits a snag in reading from the file, or 
  149.   if the file contains too many layer definitions, this routine can   
  150.   detect it and send a signal back to its caller.                     
  151. ----------------------------------------------------------------------
  152. */
  153. BEGIN
  154.    int         B_process_config(), B_create_wts();
  155.    void        B_setup_net();
  156.    Net         *result;                              /* the end product */
  157.    Layer_spec  *wts_matrix[MAX_LAYERS][MAX_LAYERS];  /* for making wts  */
  158.    Layer       *layer_ptrs[MAX_LAYERS];        /* holds ptrs to layers  */
  159.    int         num_layers, i, j;               /* actual # of layers    */
  160.  
  161.    result = (Net *) sys_alloc((unsigned)sizeof(Net));
  162.    result->ID            = ERROR;
  163.    result->num_layers    = 0;
  164.    result->input_layer   = NULL;
  165.    result->output_layer  = NULL;
  166.    result->hidden_front  = NULL;
  167.    result->hidden_back   = NULL;
  168.    result->use_biases    = TRUE;
  169.    result->num_inputs    = 0;
  170.    result->num_outputs   = 0;
  171.    result->num_io_pairs  = 0;
  172.  
  173.    for (i = 0; i < MAX_LAYERS; i++) BEGIN      /* initialize wts_matrix */
  174.       layer_ptrs[i] = NULL;                    /* and layer_ptrs array  */
  175.       for (j = 0; j < MAX_LAYERS; j++)         /* to all 'NULL' values  */
  176.          wts_matrix[i][j] = NULL;
  177.    ENDFOR
  178.  
  179.    if (B_process_config(file_name, wts_matrix, layer_ptrs, &num_layers) != OK)
  180.       return(NULL);
  181.    if (B_create_wts(wts_matrix, layer_ptrs, num_layers) != OK)
  182.       return(NULL);
  183.    B_setup_net(result, id_num, layer_ptrs, num_layers);
  184.  
  185.    return(result);
  186.  
  187. END /* B_create_net */
  188.  
  189.  
  190. int  B_process_config(file_name, wts_matrix, layer_ptrs, ptr_num_layers)
  191. char        file_name[];
  192. Layer_spec  *wts_matrix[];
  193. Layer       *layer_ptrs[];
  194. int         *ptr_num_layers;
  195. /*
  196. ----------------------------------------------------------------------
  197.  This guy processes the configuration passed in from the create_net   
  198.   routine above, creating Layers and the intermediate wt_matrix in    
  199.   the process.                                                        
  200.  Two important notes. First, note that the last argument is a pointer 
  201.   to an int. I realize that this procedure could have been made a     
  202.   function which returned the value of the int, but nearly all of the 
  203.   incoming args get modified by this routine and so I chose to remain 
  204.   consistent in how the information calculated was passed back from   
  205.   this routine (namely, via the parameters themselves).               
  206.   Second, note that this guy opens the file specified by 'file_name'  
  207.   and then uses the routine 'PS_get_layer' to read in the specs for a 
  208.   file.  Like the 'B_create_net' routine, the IO routine will return  
  209.   a negative number as one of the structure elements to indicate a    
  210.   problem in reading the file (ie, config->OK = ERROR).  Aside from  
  211.   a reading error or an incomplete layer spec, this routine also will 
  212.   check for too many layers in the input file and return an error. By 
  213.   convention, routines will return an integer indicating an error,    
  214.   unless they must return a structure, in which case an element of the
  215.   structure will be set to ERROR.    
  216.                                     
  217.  This routine returns OK if everything goes ok.  Otherwise, ERROR is   
  218.   returned.                                                           
  219. ----------------------------------------------------------------------
  220. */
  221. BEGIN
  222.    FILE        *fp;
  223.    int         i, DONE = FALSE;
  224.    Layer_spec  *config;
  225.  
  226.    if((fp = fopen(file_name, "rt")) == NULL) BEGIN
  227.       sprintf(IO_str, "\n*** can't open file %s ***\n", file_name);
  228.       IO_print(0);
  229.       return(ERROR);
  230.    ENDIF
  231.    *ptr_num_layers = 0;                       /* initialize num_layers */
  232.  
  233.    PS_reset_for_layer_parse();
  234.    if (PS_global_spec_check(fp) == ERROR)
  235.       return(ERROR);
  236.    config = PS_get_layer(fp);                 /* get first layer specs */
  237.    while ((DONE == FALSE) && (config->status != ERROR)) BEGIN
  238.       if(*ptr_num_layers == MAX_LAYERS) BEGIN
  239.          sprintf(IO_str, "\n*** too many layers ***\n");
  240.          IO_print(0);
  241.          return(ERROR);
  242.       ENDIF
  243.       (*ptr_num_layers)++; 
  244.       layer_ptrs[config->ID] = L_alloc_layer(config);
  245.       for (i = 0; i < config->num_targets; i++) 
  246.          wts_matrix[config->ID * MAX_LAYERS + config->targets[i][0]] = config;
  247.       if (config->status == EOF) DONE = TRUE; 
  248.       else config = PS_get_layer(fp);
  249.    ENDWHILE
  250.    fclose(fp);
  251.    if (config->status == ERROR) 
  252.       return(ERROR);
  253.    else return(OK);
  254.  
  255. END /* B_process_config */
  256.  
  257.  
  258. int  B_create_wts(wts_matrix, layer_ptrs, num_layers)
  259. Layer_spec  *wts_matrix[];
  260. Layer       *layer_ptrs[];
  261. int         num_layers;
  262. /*
  263. ----------------------------------------------------------------------
  264.  Refer to comments under create_net.                                  
  265.                                                                       
  266.  This routine takes the input array 'wts_matrix' and creates Weight   
  267.   structures with the appropriate information.  It also links these   
  268.   structures into the corresponding lists within the Layer structures 
  269.  NOTE that no particular order is necessary when linking the weights  
  270.   into the Layers.  Thus, new weights are simply inserted into the    
  271.   the front of the lists by using the 'W_insert_before' routine  
  272.      
  273.  Returns OK if the weights can be created, ERROR otherwise.                
  274. ----------------------------------------------------------------------
  275. */
  276. BEGIN
  277.    Weights      *new_wts;
  278.    Weights_lst  *new_wts_node;
  279.    Layer        *source, *target;
  280.    Layer_spec   *ptr_layer_spec;
  281.    int          i, j, B_check_layer_sizes();
  282.  
  283.    if (B_check_layer_sizes(wts_matrix, layer_ptrs, num_layers) == ERROR) 
  284.       return(ERROR);
  285.  
  286.    for (i = 0; i < num_layers; i++) BEGIN
  287.       source = layer_ptrs[i];
  288.       for (j = 0; j < num_layers; j++) BEGIN
  289.          ptr_layer_spec = wts_matrix[i * MAX_LAYERS + j];
  290.          if (ptr_layer_spec != NULL) BEGIN
  291.             target = layer_ptrs[j];
  292.             if ((source == NULL) || (target == NULL)) BEGIN
  293.                sprintf(IO_str, "\n*** Warning: can't create weights between %d, %d ***",
  294.                       i, j);
  295.                IO_print(0);
  296.                sprintf(IO_str, "\n*** one of the layers was never created ***\n");
  297.                IO_print(0);
  298.             ENDIF
  299.             else BEGIN
  300.                new_wts = W_alloc_weights(source, target, ptr_layer_spec);
  301.                if (new_wts->type == ERROR) return(ERROR);
  302.                new_wts_node = W_alloc_weights_lst(new_wts);
  303.                source->out_weights = 
  304.                  W_insert_before(new_wts_node, source->out_weights);
  305.                new_wts_node = W_alloc_weights_lst(new_wts);
  306.                target->in_weights = 
  307.                  W_insert_before(new_wts_node, target->in_weights);
  308.              ENDELSE
  309.          ENDIF
  310.       ENDFOR
  311.    ENDFOR
  312.    return(OK);
  313.  
  314. END /* B_create_wts */
  315.  
  316.  
  317. int  B_check_layer_sizes(wts_matrix, layer_ptrs, num_layers)
  318. Layer_spec  *wts_matrix[];
  319. Layer       *layer_ptrs[];
  320. int         num_layers;
  321. /*
  322. ----------------------------------------------------------------------
  323.  This routine checks through all of the layers, noting the layer with 
  324.   the most nodes.  This number is then used to calculate the weight   
  325.   range for initializing the random weights.  The whole concept for   
  326.   this routine comes from the formula for calculating the output of a 
  327.   node:  output = f(SUM) where SUM = sum i,j [ Wij * Oi].  That is,   
  328.   you sum all of the incoming weight/output products, and the result  
  329.   is a sum fed through the semi linear activation function above.     
  330.   Problems arise if this SUM is much greater than 10 because the      
  331.   activation function starts to reach 0 or 1 at that point.  Thus, we 
  332.   want to set our weights so that problem doesn't occur.  Taking the  
  333.   worst case, we would have all of the output values "Oi" at .9, and  
  334.   all of the weights the same.  That gives:    
  335.                          
  336.        10 = .9 * (num_weights) * (weight value).   
  337.                           
  338.   Two conclusions can be drawn from the above.  First, if you let the 
  339.   weights be as small as possible, you can find the maximum number of 
  340.   nodes allowable in a layer, since this program generates a weight   
  341.   for each node of a layer.  That makes the maximum number of nodes   
  342.   about equal to 10 * 10^precision where 'precision' is equal to the  
  343.   the number of significant digits after the decimal point that the   
  344.   the Sint configuration allows (Thus for a Sint with 3 sig figs, you 
  345.   get a maximum layer size of 10 * 10^3 or 10,000).                   
  346.   The second conclusion we can draw is that, given the maximum number 
  347.   of nodes in a layer, we can determine the range of values which the 
  348.   initial weights should have.  That is what is done here.            
  349.  Note: this routine returns 0 if all goes well, otherwise 1.          
  350. ----------------------------------------------------------------------
  351. */
  352. BEGIN
  353.    int         i, j, k;
  354.    int         max, temp;
  355.    Layer_spec  *ptr_layer_spec;
  356.    Layer       *source, *target;
  357.  
  358.    max = 0;
  359.    /*----------------------------------------*/
  360.    /* find the maximum number of connections */
  361.    /* per node by looping through all the    */
  362.    /* layer specs in the wts_matrix variable */
  363.    /*----------------------------------------*/
  364.    for (i = 0; i < num_layers; i++) BEGIN
  365.       source = layer_ptrs[i];
  366.       for (j = 0; j < num_layers; j++) BEGIN
  367.          ptr_layer_spec = wts_matrix[i * MAX_LAYERS + j];
  368.          if (ptr_layer_spec != NULL) BEGIN
  369.             target = layer_ptrs[j];
  370.             /*----------------------------------------------------*/
  371.             /* find the corresponding target in the targets array */
  372.             /*----------------------------------------------------*/
  373.             for (k = 0; k < ptr_layer_spec->num_targets; k++)
  374.                if (ptr_layer_spec->targets[k][0] == target->ID)
  375.                   break;
  376.             /*----------------------------------*/
  377.             /* now we check the connection type */
  378.             /* by looking at targets array [0]  */
  379.             /* if 0 (connect all) then the num  */
  380.             /* of connections = source_nodes.   */
  381.             /*----------------------------------*/        
  382.             if (ptr_layer_spec->targets[k][1] == 0)
  383.                temp = source->num_nodes;
  384.             else
  385.                /*-------------------------------------*/
  386.                /* if targets[k][0] != 0, then we have */
  387.                /* a patterned scheme. targets[1] and  */
  388.                /* targets[2] hold P & Q, respecitvely */
  389.                /* and P * Q = num of connections      */
  390.                /*-------------------------------------*/
  391.                temp = ptr_layer_spec->targets[k][1]
  392.                        * ptr_layer_spec->targets[k][2];
  393.             /*----------------------------------*/
  394.             /* use temp to set the max_incoming */
  395.             /* field of the TARGET layer        */
  396.             /*----------------------------------*/
  397.             target->max_incoming = temp;
  398.             max = ((temp > max) ? temp : max);
  399.          ENDIF
  400.       ENDFOR
  401.    ENDFOR
  402.  
  403.    /*-----------------------------------*/
  404.    /* check the number of connections   */
  405.    /* to see if it's too large for NETS */
  406.    /*-----------------------------------*/
  407.    if (max > MAX_NODES) BEGIN
  408.       sprintf(IO_str, "\n*** Layers are too large; reduce the nodes in each layer to within %d ***\n",
  409.               MAX_NODES);
  410.       IO_print(0);
  411.       return(ERROR);
  412.    ENDIF
  413.    W_weight_range(max);
  414.    return(OK);
  415.  
  416. END /* B_check_layer_sizes */
  417.  
  418.  
  419. void  B_setup_net(ptr_net, id_num, layer_ptrs, num_layers)
  420. Net    *ptr_net;
  421. int    id_num;
  422. Layer  *layer_ptrs[];
  423. int    num_layers;
  424. /*
  425. ----------------------------------------------------------------------
  426.  This routine collects all the data created by the other two routines 
  427.   and assembles it into the net structure pointed to by 'ptr_net'. The 
  428.   final product is NOT a completely initialized net structure. The    
  429.   input/output pairs for learning are not yet present.                
  430.  There really is nothing hard going on here; most of the work has     
  431.   already been done at this point by 'B_process_config' and           
  432.   'B_create_wts'.                                                     
  433.   All that is left is to proceed through the layer_ptrs array and in- 
  434.   sert those layers into the net.  Of course, the id, learn_rate, and 
  435.   momentum must also be set.                                           
  436.  Two notes: first, notice that the learn_rates and momentum must be con-
  437.   verted into Sint format, since this is our internal representation  
  438.   for floating point numbers (see Sint in 'netpool.h'). Also, note    
  439.   that it is ASSUMED THAT THE LAYERS IN THE layer_ptrs ARRAY ARE IN   
  440.   THE ORDER THEY SHOULD BE COMPUTED.  This assumption carries all the 
  441.   way back to the actual input, since that input is also assumed to   
  442.   be in the correct order (ie, nothing is done at ANY stage of the net
  443.   creation to set an order).  This is absolutely essential for the    
  444.   calculations on the net to be done correctly.  Lastly, since order  
  445.   is so important, we cannot simply use an 'insert_before' routine for
  446.   placing the layers into the net.  Instead, we have to work BACKWARDS
  447.   from the end of the array while using 'insert_before'.              
  448.  Also, note that at least two layers are assumed to be present in the 
  449.   array of layer pointers, namely the input and output layers.  A net 
  450.   without at least these would be ridiculous anyway.  By convention,  
  451.   these two layers are assumed to be layer 0 and 1, respectively, in  
  452.   the layer_ptrs array.  Layers 0 and 1 ARE linked into the hidden    
  453.   list (even though they are not hidden) since they are both included 
  454.   included in the forward and backward propagation steps. Actually,   
  455.   layer 1 is included in forward prop, layer 0 in backward prop. Once 
  456.   all the layers have been linked into the hidden list, the two ends  
  457.   of the list are moved in by one.  This is because we want the front 
  458.   of the list to point to the first layer of forward propagation, not 
  459.   layer 0.  The same is true for backward propagation at the other end
  460.   of the list.                                                        
  461. ----------------------------------------------------------------------
  462. */
  463. BEGIN
  464.    void       B_setup_learning();
  465.    Layer_lst  *new_layer_node;
  466.    int        i;
  467.    char       tmp_str[MAX_WORD_SIZE];
  468.  
  469.    /*-----------------------------------*/
  470.    /* if no input layer or output layer */
  471.    /* specified, then return error      */
  472.    /*-----------------------------------*/
  473.    if (layer_ptrs[IN_LAYER] == 0) BEGIN
  474.       sprintf(IO_str, "\n*** ERROR, no input layer ***\n");
  475.       IO_print(0);
  476.       return;
  477.    ENDIF
  478.    if (layer_ptrs[OUT_LAYER] == 0) BEGIN
  479.       sprintf(IO_str, "\n*** ERROR, no output layer ***\n");
  480.       IO_print(0);
  481.       return;
  482.    ENDIF
  483.  
  484.    /*----------------------*/
  485.    /* setup learning rates */
  486.    /*----------------------*/
  487.    B_setup_learning(layer_ptrs, num_layers);
  488.  
  489. #if  !DELIVERY
  490.    /*------------------------------------------------*/
  491.    /* if not in delivery mode, prompt for bias value */
  492.    /*------------------------------------------------*/
  493.    sprintf(IO_str, "\n   Use biases in network(y/n, default=y)? ");
  494.    IO_print(0);
  495.    IO_my_get_string(tmp_str);
  496.    if (tmp_str[0] != ENDSTRING)
  497.       if ( (tmp_str[0] == 'y') || (tmp_str[0] == 'Y') )
  498.          ptr_net->use_biases = TRUE;
  499.       else
  500.          ptr_net->use_biases = FALSE;
  501. #endif
  502.  
  503.    /*--------------------------------------*/
  504.    /* set the rest of the network elements */
  505.    /*--------------------------------------*/
  506.    ptr_net->ID            = id_num;
  507.    ptr_net->num_layers    = num_layers;
  508.    ptr_net->input_layer   = layer_ptrs[IN_LAYER];
  509.    ptr_net->output_layer  = layer_ptrs[OUT_LAYER];
  510.    
  511.    /*-------------------------------------------*/
  512.    /* link the output layer to the hidden lists */
  513.    /*-------------------------------------------*/
  514.    ptr_net->hidden_back   = L_alloc_layer_lst(layer_ptrs[OUT_LAYER]);
  515.    ptr_net->hidden_front  = L_insert_before(ptr_net->hidden_back, NULL); 
  516.  
  517.    /*--------------------------------------*/
  518.    /* link the hidden layers into the list */
  519.    /*--------------------------------------*/
  520.    for (i = (num_layers-1); i > 1; i--) BEGIN
  521.       new_layer_node = L_alloc_layer_lst(layer_ptrs[i]);
  522.       ptr_net->hidden_front = L_insert_before(new_layer_node,
  523.                                              ptr_net->hidden_front);
  524.    ENDFOR
  525.    
  526.    /*-------------------------------------------*/
  527.    /* link the rest of the layers into the list */
  528.    /*-------------------------------------------*/
  529.    new_layer_node = L_alloc_layer_lst(layer_ptrs[IN_LAYER]);
  530.    ptr_net->hidden_front = L_insert_before(new_layer_node,
  531.                                           ptr_net->hidden_front);
  532.  
  533.    ptr_net->hidden_front  = ptr_net->hidden_front->next;
  534.    ptr_net->hidden_back   = ptr_net->hidden_back->prev;
  535.  
  536. END /* B_setup_net */
  537.  
  538.  
  539. void  B_setup_learning(layer_ptrs, num_layers)
  540. Layer  *layer_ptrs[];
  541. int    num_layers;
  542. /*
  543. ----------------------------------------------------------------------
  544.   This routine loops through the layers twice. The first time it records
  545.   the maximum number of weights found coming into any layer for calculating
  546.   default values. This is done if global values were not specified by
  547.   the user. Next, the second loop through the layers is performed so 
  548.   that all layers are given some learning rate and momentum. 
  549.   Two items are of note here. First, note that if the user does not
  550.   enter a scale value then a default is NOT used here. Second, note
  551.   that the "cur_learn" field IS NOT SET BEFORE THIS ROUTINE CALL. Thus,
  552.   the second loop through the layers must be performed even if the global
  553.   values were defined by the user (I had originally thought that this
  554.   second loop could be skipped if both globals were already defined since
  555.   the B_process_config routine would have already set the learn and 
  556.   momentum values base on the global defaults. But, alas, I forgot about
  557.   the cur_learn field!).
  558. ----------------------------------------------------------------------
  559. */
  560. BEGIN
  561.    void   B_set_layer_learning(), B_set_layer_momentum();
  562.    int    i, max_wts;
  563.    Layer  *cur_layer;
  564.  
  565.    /*------------------------------------------*/
  566.    /* loop through layers to find max weights  */
  567.    /* then calc learning and momentum defaults */
  568.    /*------------------------------------------*/
  569.    max_wts = 0;
  570.    for (i = 1; i < num_layers; i++)      
  571.       max_wts = (layer_ptrs[i]->max_incoming > max_wts)
  572.                 ? layer_ptrs[i]->max_incoming : max_wts;
  573.    
  574.    /*----------------------------------------*/
  575.    /* loop through all layers, setting the   */
  576.    /* learn rate and momentum if not defined */
  577.    /*----------------------------------------*/
  578.    for (i = 1; i < num_layers; i++) BEGIN
  579.       cur_layer = layer_ptrs[i];
  580.       B_set_layer_learning(cur_layer, max_wts);
  581.       B_set_layer_momentum(cur_layer, max_wts);
  582.    ENDFOR
  583.    
  584. END /* B_setup_learning */
  585.  
  586.  
  587. void  B_set_layer_learning(ptr_layer, max_wts)
  588. Layer  *ptr_layer;
  589. int     max_wts;
  590. /*
  591. ----------------------------------------------------------------------
  592.   Given a pointer to a layer and the maximum weights connected to a
  593.   node in the network, this routine goes through the motion of checking
  594.   the state of the current layer to see if the user should be prompted
  595.   for learning rates and/or scale values. Essentially, there are eight
  596.   possible cases, depending upon the states of three values: the global
  597.   learning base, the learn_base for the layer, and the learn_scale for
  598.   the layer. The actions for these cases are as follows: (note that
  599.   G = global_learn_base, L=layer learn_base, S=layer scale_base, and
  600.   "N" means not defined, "Y" means defined)
  601.   
  602.   G L S   Action taken
  603.   -----   ------------
  604.   Y Y Y   do nothing
  605.   Y Y N   set learn_scale = 0
  606.   Y N Y   set learn_base = G
  607.   Y N N   set learn_base = G, set learn_scale = 0
  608.   N Y Y   do nothing
  609.   N Y N   set learn_scale = 0
  610.   N N Y   prompt for G/L; global default prompt for G, local for L
  611.   N N N   prompt for G/L/S; global for G, local for L, default for S,L
  612.   
  613.   Note that default values can be figured either on a global basis
  614.   (using max_wts) or on a local basis based on the maximum incoming 
  615.   weights FOR THE LAYER. Also, a default scale can be figured from a
  616.   learning rate and vice-versa when needed. 
  617.   Finally, note that this routine keeps track of a "prompt_state"
  618.   variable so that it only prompts the user once to ask whether or not
  619.   he/she wants a global learning rate. Using a static variable, one 
  620.   can reset its state every time a new net is created and its value 
  621.   will be retained between calls for each layer of a single network.
  622. ----------------------------------------------------------------------
  623. */
  624. BEGIN
  625.    static float  prompt_state = TRUE;
  626.    float         learn, scale;
  627.    char          tmp_str[MAX_WORD_SIZE];
  628.    
  629.    /*--------------------------------------*/
  630.    /* reset the state of g_learn_state if  */
  631.    /* we are starting a new network. If so */
  632.    /* then we will be starting w/layer 1   */
  633.    /*--------------------------------------*/
  634.    if (ptr_layer->ID == 1)
  635.       prompt_state = TRUE;
  636.    
  637.    /*-------------------------------------------*/
  638.    /* handles the top half of the table in the  */
  639.    /* comment, setting the learning base to the */
  640.    /* global learning rate and the learing rate */
  641.    /* to 0 (zero) if it's undefined.            */
  642.    /*-------------------------------------------*/
  643.    if (global_learn_base != UNDEFINED) BEGIN
  644.       if (ptr_layer->learn_base == UNDEFINED)
  645.          ptr_layer->learn_base = global_learn_base;
  646.       if (ptr_layer->learn_scale == UNDEFINED)
  647.          ptr_layer->learn_scale = 0;
  648.    ENDIF
  649.    
  650.    else BEGIN
  651.       /*--------------------------------------------------*/
  652.       /* handle cases 5 and 6 of the table in the comment */
  653.       /* In these cases, just set the scale if undefined  */
  654.       /*--------------------------------------------------*/
  655.       if (ptr_layer->learn_base != UNDEFINED) BEGIN
  656.          if (ptr_layer->learn_scale == UNDEFINED)
  657.             ptr_layer->learn_scale = 0;
  658.       ENDIF
  659.       
  660.       else BEGIN
  661.          /*----------------------------------------*/
  662.          /* for the last two cases, if user hasn't */
  663.          /* been prompted for global, then prompt  */
  664.          /*----------------------------------------*/
  665.          if (prompt_state == TRUE) BEGIN
  666.             prompt_state = FALSE;
  667.             sprintf(IO_str, "\n   Use a global learning rate (y/n, default=y)? ");
  668.             IO_print(0);
  669.             IO_my_get_string(tmp_str);
  670.             
  671.             if ((tmp_str[0] == ENDSTRING)
  672.                  || (tmp_str[0] == 'y') || (tmp_str[0] == 'Y')) BEGIN
  673.                /*-------------------------------------*/
  674.                /* if global is selected, then prompt  */
  675.                /* and use value as default learn rate */
  676.                /*-------------------------------------*/
  677.                learn = LR_learn_default(max_wts);
  678.                sprintf(IO_wkstr, "\n   Enter global learning rate (default=%%.f): ");
  679.                IO_insert_format(IO_wkstr);
  680.                sprintf(IO_str, IO_wkstr, learn);
  681.                IO_print(0);
  682.                global_learn_base = IO_get_default_float(learn);
  683.                ptr_layer->learn_base = global_learn_base;
  684.                if (ptr_layer->learn_scale == UNDEFINED)
  685.                   ptr_layer->learn_scale = 0;
  686.             ENDIF
  687.          ENDIF
  688.          
  689.          /*----------------------------------------------*/
  690.          /* if the global is still undefined, that means */
  691.          /* the user has elected against a global learn  */
  692.          /*----------------------------------------------*/
  693.          if (global_learn_base == UNDEFINED) BEGIN
  694.             
  695.             /*---------------------------------------*/
  696.             /* first, prompt for default learn value */
  697.             /*---------------------------------------*/
  698.             if (ptr_layer->learn_scale == UNDEFINED) BEGIN
  699.                learn = LR_learn_default(ptr_layer->max_incoming);
  700.                sprintf(IO_str, "\n   Use constant learning rate for layer ");
  701.                IO_print(0);
  702.                sprintf(IO_str, "%d (y/n, default=y)? ", ptr_layer->ID);
  703.                IO_print(0);
  704.                IO_my_get_string(tmp_str);
  705.  
  706.                /*-----------------------------------------*/
  707.                /* if denied, then the user wants a varied */
  708.                /* learning rate. Divide default by 2. If  */
  709.                /* "y", the constant learn; set scale = 0. */
  710.                /*-----------------------------------------*/
  711.                if ((tmp_str[0] != ENDSTRING) 
  712.                    && (tmp_str[0] != 'y') && (tmp_str[0] != 'Y'))
  713.                   learn = learn / 2.0;
  714.                else ptr_layer->learn_scale = 0;
  715.             ENDIF
  716.             else          
  717.                learn = LR_learn_from_scale(ptr_layer->learn_scale);
  718.  
  719.             /*-----------------------------------------------*/
  720.             /* prompt for the learning rate based on default */
  721.             /*-----------------------------------------------*/
  722.             sprintf(IO_str, "\n     Enter learning rate for layer ");
  723.             IO_print(0);
  724.             sprintf(IO_wkstr, "%d (default=%%.f): ", ptr_layer->ID);
  725.             IO_insert_format(IO_wkstr);
  726.             sprintf(IO_str, IO_wkstr, learn);
  727.             IO_print(0);
  728.             ptr_layer->learn_base = IO_get_default_float(learn);
  729.             
  730.             /*-------------------------------------*/
  731.             /* finally, prompt for the learn_scale */
  732.             /* if it is undefined at this point    */
  733.             /*-------------------------------------*/
  734.             if (ptr_layer->learn_scale == UNDEFINED) BEGIN
  735.                scale = LR_scale_default(ptr_layer->learn_base);
  736.                sprintf(IO_str, "\n     Enter scaling factor for layer ");
  737.                IO_print(0);
  738.                sprintf(IO_wkstr, "%d (default=%%.f): ", ptr_layer->ID);
  739.                IO_insert_format(IO_wkstr);
  740.                sprintf(IO_str, IO_wkstr, scale);
  741.                IO_print(0);
  742.                ptr_layer->learn_scale = IO_get_default_float(scale);
  743.             ENDIF
  744.          ENDIF
  745.       ENDELSE
  746.    ENDELSE
  747.    
  748.    /*-------------------------------------*/
  749.    /* when the dust clears, set the first */
  750.    /* learning rate value for the layer   */
  751.    /*-------------------------------------*/
  752.    ptr_layer->cur_learn = (D_Sint)C_float_to_Sint(ptr_layer->learn_base);
  753.       
  754. END /* B_set_layer_learning */
  755.  
  756.  
  757. void  B_set_layer_momentum(ptr_layer, max_wts)
  758. Layer  *ptr_layer;
  759. int   max_wts;
  760. /*
  761. ----------------------------------------------------------------------
  762.   Sets the momentum value for the layer, given a pointer to the layer
  763.   and the maximum weights connected into a node in the network. There 
  764.   are four cases which must be handled, based on the values of the 
  765.   global momentum (G) and the local momentum defined for the layer (M).
  766.   The table below gives the appropriate actions for the four states, 
  767.   based upon whether or not G,M are specified ("Y") or not ("N"):
  768.   
  769.   G M     Action
  770.   ---     -------
  771.   Y Y     do nothing
  772.   Y N     set momemtum = G
  773.   N Y     do nothing
  774.   N N     prompt for global G, set momentum to G or prompt for local.
  775.   
  776.   As with the B_set_layer_learning routine, the last case prompts the
  777.   user for a global momentum ONLY ONCE by keeping track of a local static
  778.   variable on the prompt_state. 
  779. ----------------------------------------------------------------------
  780. */
  781. BEGIN
  782.    static float  prompt_state = TRUE;
  783.    float         momentum;
  784.    char          tmp_str[MAX_WORD_SIZE];
  785.    
  786.    /*--------------------------------------*/
  787.    /* reset the state of g_learn_state if  */
  788.    /* we are starting a new network. If so */
  789.    /* then we will be starting w/layer 1   */
  790.    /*--------------------------------------*/
  791.    if (ptr_layer->ID == 1)
  792.       prompt_state = TRUE;
  793.       
  794.    if (ptr_layer->momentum == UNDEFINED) BEGIN
  795.       /*------------------------------------------*/
  796.       /* if user hasn't been prompted, then do so */
  797.       /*------------------------------------------*/
  798.       if ((prompt_state == TRUE) && (global_momentum == UNDEFINED)) BEGIN
  799.          prompt_state = FALSE;
  800.          sprintf(IO_str, "\n   Use a global momentum (y/n, default=y)? ");
  801.          IO_print(0);
  802.          IO_my_get_string(tmp_str);
  803.             
  804.          if ((tmp_str[0] == ENDSTRING)
  805.               || (tmp_str[0] == 'y') || (tmp_str[0] == 'Y')) BEGIN
  806.             /*-------------------------------------*/
  807.             /* if global is selected, then prompt  */
  808.             /* and use value as default momentum   */
  809.             /*-------------------------------------*/
  810.             momentum = LR_momentum_default(max_wts);         
  811.             sprintf(IO_wkstr, "\n   Enter global momentum (default=%%.f): ");
  812.             IO_insert_format(IO_wkstr);
  813.             sprintf(IO_str, IO_wkstr, momentum);
  814.             IO_print(0);
  815.             global_momentum = IO_get_default_float(momentum);
  816.          ENDIF
  817.       ENDIF
  818.       
  819.       if (global_momentum != UNDEFINED) 
  820.          ptr_layer->momentum = global_momentum;
  821.       else BEGIN
  822.          /*---------------------------------------------*/
  823.          /* if global undefined, then local momentum    */
  824.          /* is desired. Calc default using max incoming */
  825.          /*---------------------------------------------*/
  826.          momentum = LR_momentum_default(ptr_layer->max_incoming);
  827.          sprintf(IO_str, "\n     Enter momentum for layer ");
  828.          IO_print(0);
  829.          sprintf(IO_str, "%d (default=%%.f): ", ptr_layer->ID);
  830.          IO_insert_format(IO_wkstr);
  831.          sprintf(IO_str, IO_wkstr, momentum);
  832.          IO_print(0);
  833.          ptr_layer->momentum = IO_get_default_float(momentum);         
  834.       ENDELSE
  835.    ENDIF
  836.    
  837. END /* B_set_layer_momentum */
  838.       
  839.  
  840. Net  *B_free_net(ptr_net)
  841. Net  *ptr_net;
  842. /*
  843. ----------------------------------------------------------------------
  844.   The purpose of this routine is memory management. It frees the memory
  845.    allocated to a network specified by the network pointer and resets 
  846.    the pointer to NULL. 
  847.   To accomplish this task, this routine passes the buck to the
  848.    L_free_layer_lst routine which simply loops through all of the
  849.    layers of the network calling L_free_layer for each. Note that the
  850.    weights are doubly referenced and can thus cause a problem. To avoid
  851.    freeing something twice, I use the convention of freeing only a layer's
  852.    INCOMING weights. This means that the INPUT LAYER can be SKIPPED by
  853.    this routine( see L_free_layer_lst for details ).
  854.   NOTE: The OUTPUT layer is included in the list of hidden layers. Recall
  855.    that the list "hidden_front" includes all those layers which must be
  856.    updated for a forward propagation. This includes the output layer. 
  857.    Thus there is an implicit freeing of the output layer when the hidden
  858.    layers are freed.
  859. ----------------------------------------------------------------------
  860. */
  861. BEGIN
  862.    if (ptr_net == NULL) return(NULL);
  863.    
  864.    L_free_layer(ptr_net->input_layer);
  865.    L_free_layer_lst(ptr_net->hidden_front);   
  866.    
  867.    sys_free((char *)ptr_net);
  868.    return(NULL);
  869.  
  870. END /* B_free_net */
  871.